/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.utils;

import com.alibaba.fastjson.JSON;
import org.apache.commons.io.IOUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class HttpUtil {

    private static final Logger logger = LoggerFactory.getLogger(HttpUtil.class);

    private static int SocketTimeout = -1;//3秒
    private static int ConnectTimeout = -1;//3秒
    private static Boolean SetTimeOut = true;

    private static CloseableHttpClient getHttpClient() {
        RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder.<ConnectionSocketFactory>create();
        ConnectionSocketFactory plainSF = new PlainConnectionSocketFactory();
        registryBuilder.register("http", plainSF);
        //指定信任密钥存储对象和连接套接字工厂
        try {
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            //信任任何链接
            TrustStrategy anyTrustStrategy = new TrustStrategy() {
                @Override
                public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
                    return true;
                }
            };
            SSLContext sslContext = SSLContexts.custom().useTLS().loadTrustMaterial(trustStore, anyTrustStrategy).build();
            LayeredConnectionSocketFactory sslSF = new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            registryBuilder.register("https", sslSF);
        } catch (KeyStoreException | NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        } catch (KeyManagementException e) {
            throw new RuntimeException(e);
        }
        Registry<ConnectionSocketFactory> registry = registryBuilder.build();
        //设置连接管理器
        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(registry);
        //		connManager.setDefaultConnectionConfig(connConfig);
        //		connManager.setDefaultSocketConfig(socketConfig);
        //构建客户端
        return HttpClientBuilder.create().setConnectionManager(connManager).build();
    }

    public static Object get(String url) {
        return get(url, null);
    }

    /**
     * get
     *
     * @param url     请求的url
     * @param queries 请求的参数，在浏览器？后面的数据，没有可以传null
     * @return
     * @throws IOException
     */
    public static Object get(String url, Map<String, String> queries) {
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        try {
            //支持https
            httpClient = getHttpClient();
            StringBuilder sb = new StringBuilder(url);
            if (queries != null && queries.keySet().size() > 0) {
                boolean firstFlag = true;
                Iterator iterator = queries.entrySet().iterator();
                while (iterator.hasNext()) {
                    Map.Entry entry = (Map.Entry<String, String>) iterator.next();
                    if (firstFlag) {
                        sb.append("?" + (String) entry.getKey() + "=" + (String) entry.getValue());
                        firstFlag = false;
                    } else {
                        sb.append("&" + (String) entry.getKey() + "=" + (String) entry.getValue());
                    }
                }
            }
            HttpGet httpGet = new HttpGet(sb.toString());
            if (SetTimeOut) {
                RequestConfig requestConfig = RequestConfig.custom()
                        .setSocketTimeout(SocketTimeout)
                        .setConnectTimeout(ConnectTimeout).build();//设置请求和传输超时时间
                httpGet.setConfig(requestConfig);
            }
            //请求数据
            response = httpClient.execute(httpGet);
            int status = response.getStatusLine().getStatusCode();
            if (status == HttpStatus.SC_OK) {
                HttpEntity entity = response.getEntity();
                ContentType contentType = ContentType.getOrDefault(entity);
                if (isByteArrayContent(contentType.getMimeType())) {
                    return EntityUtils.toByteArray(entity);
                } else {
                    // do something useful with the response body
                    // and ensure it is fully consumed
                    String content = EntityUtils.toString(entity);
                    if (contentType.getMimeType().equals(ContentType.APPLICATION_JSON.getMimeType()) || content.startsWith("{") && content.endsWith("}")) {
                        if (content.startsWith("[") && content.endsWith("]"))
                            return JSON.parseObject(content, List.class);
                        return JSON.parseObject(content, Map.class);
                    }
                    return content;
                }
                //EntityUtils.consume(entity);
            } else {
                if (logger.isDebugEnabled())
                    logger.debug("http return status error:" + status);
            }
        } catch (Exception e) {
            if (logger.isErrorEnabled())
                logger.error("post", e);
        } finally {
            if (response != null)
                IOUtils.closeQuietly(response);
            if (httpClient != null)
                IOUtils.closeQuietly(httpClient);
        }
        return null;
    }

    private static boolean isByteArrayContent(String mimeType) {
        if (mimeType.startsWith("text/") || mimeType.contains("json") || mimeType.contains("xml"))
            return false;
        return true;
    }

    public static Object post(String url, Object params) {
        return post(url, null, params);
    }

    /**
     * post
     *
     * @param url     请求的url
     * @param queries 请求的参数，在浏览器？后面的数据，没有可以传null
     * @param params  post form 提交的参数
     * @return
     * @throws IOException
     */
    public static Object post(String url, Map<String, String> queries, Object params) {
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        try {
            //支持https
            httpClient = getHttpClient();
            StringBuilder sb = new StringBuilder(url);

            if (queries != null && queries.keySet().size() > 0) {
                boolean firstFlag = true;
                Iterator iterator = queries.entrySet().iterator();
                while (iterator.hasNext()) {
                    Map.Entry entry = (Map.Entry<String, String>) iterator.next();
                    if (firstFlag) {
                        sb.append("?" + (String) entry.getKey() + "=" + (String) entry.getValue());
                        firstFlag = false;
                    } else {
                        sb.append("&" + (String) entry.getKey() + "=" + (String) entry.getValue());
                    }
                }
            }

            //指定url,和http方式
            HttpPost httpPost = new HttpPost(sb.toString());
            if (SetTimeOut) {
                RequestConfig requestConfig = RequestConfig.custom()
                        .setSocketTimeout(SocketTimeout)
                        .setConnectTimeout(ConnectTimeout).build();//设置请求和传输超时时间
                httpPost.setConfig(requestConfig);
            }
            if (params instanceof Map) {
                Map<String, String> map = (Map<String, String>) params;
                //添加参数
                List<NameValuePair> nvps = new ArrayList<NameValuePair>();
                if (params != null && map.keySet().size() > 0) {
                    Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
                    while (iterator.hasNext()) {
                        Map.Entry<String, String> entry = (Map.Entry<String, String>) iterator.next();
                        nvps.add(new BasicNameValuePair((String) entry.getKey(), (String) entry.getValue()));
                    }
                }
                httpPost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8));
            } else if (params instanceof String) {
                StringEntity entity = new StringEntity((String) params, "UTF-8");   // 中文乱码在此解决
                entity.setContentType("application/json");
                httpPost.setEntity(entity);
            }
            //请求数据
            response = httpClient.execute(httpPost);
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                HttpEntity entity = response.getEntity();
                ContentType contentType = ContentType.getOrDefault(entity);
                if (isByteArrayContent(contentType.getMimeType())) {
                    return EntityUtils.toByteArray(entity);
                } else {
                    String content = EntityUtils.toString(entity);
                    if (contentType.getMimeType().equals(ContentType.APPLICATION_JSON.getMimeType()) || content.startsWith("{") && content.endsWith("}")) {
                        if (content.startsWith("[") && content.endsWith("]"))
                            return JSON.parseObject(content, List.class);
                        return JSON.parseObject(content, Map.class);
                    }
                    return content;
                }
                //EntityUtils.consume(entity);
            } else {
                if (logger.isDebugEnabled())
                    logger.debug("http return status error:" + response.getStatusLine().getStatusCode());
            }
        } catch (Exception e) {
            if (logger.isErrorEnabled())
                logger.error("post", e);
        } finally {
            if (httpClient != null)
                IOUtils.closeQuietly(httpClient);
            if (response != null)
                IOUtils.closeQuietly(response);
        }
        return null;
    }
}
